/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cmp.player.controls;

import static com.cmp.core.constants.InputUIDConstants.*;
import com.cmp.logging.LoggerControl;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import static java.util.logging.Level.*;
import java.util.logging.Logger;

/**
 * Handles everything related target picking and mouse position. I guess
 * @author krummer
 */
public class CursorSelectionControl extends AbstractControl {
    private static final String ROOT_KEY = "cursorRoot";
    
    private CharacterRigidBodyControl body;
    private boolean hasViewDirectionChanged;
    private float rootDuration;
    private static final Logger logger = Logger.getLogger(CursorSelectionControl.class.getName());
    
    static {
        logger.addHandler(LoggerControl.getConsoleHandler());
        logger.setLevel(FINEST);
    }
    
    
    @Override
    public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        
        this.rootDuration = 0.f;
        body = this.getSpatial().getControl(CharacterRigidBodyControl.class);    
    }
    
    /**
     * Gets you the node of the oject your mouse is on.
     * uses a ray cast, so don't overdo it.
     * @return the object your mouse is hover over
     */
    public Node getSelection() {
        Node result = null;
        
        // 1. Reset results list.
        CollisionResults results = new CollisionResults();
        // 2. Aim the ray from mouse pos down.
        Vector3f cursorPos = this.getSpatial().getUserData(CURSOR_POS_UID);
        Ray ray = new Ray(cursorPos.add(Vector3f.UNIT_Y.mult(3.f)), Vector3f.UNIT_Y.negate());
        // 3. Collect intersections between Ray and Shootables in results list.
        getSpatial().getParent().collideWith(ray, results);       
        // 4. find closest
        if (results.size() > 0) {
          // The closest collision point is what was truly hit:
          CollisionResult closest = results.getClosestCollision();
          result = closest.getGeometry().getParent().getParent().getParent();
        }
        
        return result;
    }
    
    /**
     * lock/unlock movements
     * @param root is locked ?
     */
    public void setRooted(boolean root, float duration) {
        this.getSpatial().setUserData(ROOT_KEY, root);
        this.rootDuration = duration;
    }
    
    public boolean isRooted() {
        return super.getSpatial().getUserData(ROOT_KEY);
    }
    
    
    @Override
    protected void controlUpdate(float tpf) {
        Vector3f contact = super.getSpatial().getUserData(CURSOR_POS_UID);
        if(contact != null && !(this.isRooted())) {
            //set y of contact point to spatial height to avoid nodding of mesh
            contact.setY(body.getPhysicsLocation().getY());
            //reorientate spatial
            spatial.lookAt(contact, Vector3f.UNIT_Y);
            //reorientate physics
            if (body.getMotionState().isApplyPhysicsLocal()) {
                body.setPhysicsRotation(spatial.getLocalRotation());
            } else {
                body.setPhysicsRotation(spatial.getWorldRotation());
            }
            logger.log(FINEST, "contact = {0}", contact);
        }  else if(this.isRooted()) {
            this.rootDuration -= tpf;
            if(this.rootDuration < 0.f) {
                this.rootDuration = 0.f;
                this.setRooted(false, 0f);
            }
        }         

    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {

    }

    public Control cloneForSpatial(Spatial spatial) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
}
